package com.xxjqr.rbac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.xxjqr.rbac.entity.dto.MenuDto;
import com.xxjqr.rbac.entity.pojo.TbMenu;
import com.xxjqr.rbac.entity.pojo.TbRoleMenuRel;
import com.xxjqr.rbac.entity.vo.MenuListVo;
import com.xxjqr.rbac.enums.MenuTypeEnum;
import com.xxjqr.rbac.enums.StatusEnum;
import com.xxjqr.rbac.exception.CommonException;
import com.xxjqr.rbac.mapper.TbMenuMapper;
import com.xxjqr.rbac.mapper.TbRoleMenuRelMapper;
import com.xxjqr.rbac.service.TbMenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxjqr.rbac.util.SnowIdUtil;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * <p>
 * 菜单表 服务实现类
 * </p>
 *
 * @author 丁昌江
 * @since 2021-01-22
 */
@Service
@AllArgsConstructor
public class TbMenuServiceImpl extends ServiceImpl<TbMenuMapper, TbMenu> implements TbMenuService {

    private final TbMenuMapper menuMapper;
    private final TbRoleMenuRelMapper roleMenuRelMapper;

    @Override
    @SuppressWarnings("unchecked")
    public List<MenuListVo> getMenuTree(String name, StatusEnum status) {
        LambdaQueryWrapper<TbMenu> queryWrapper = new LambdaQueryWrapper<TbMenu>()
                .orderByAsc(TbMenu::getLevel, TbMenu::getSort)
                .eq(TbMenu::getIsDelete, 0);
        if (StringUtils.isNotEmpty(name)) {
            queryWrapper.like(TbMenu::getName, name);
        }
        if (status != null) {
            queryWrapper.eq(TbMenu::getStatus, status);
        }
        List<TbMenu> allMenu = baseMapper.selectList(queryWrapper);
        if (status == StatusEnum.DISABLE) {
            List<MenuListVo> menuVoList = new ArrayList<>();
            for (TbMenu menu : allMenu) {
                MenuListVo menuVo = new MenuListVo();
                BeanUtils.copyProperties(menu, menuVo);
                menuVoList.add(menuVo);
            }
            return menuVoList;
        }
        // 0L：表示根节点的父ID
        List<MenuListVo> menuVos = transferMenuVo(allMenu, 0L);
        return menuVos;
    }

    private List<MenuListVo> transferMenuVo(List<TbMenu> allMenu, Long parentId) {
        List<MenuListVo> resultList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(allMenu)) {
            for (TbMenu source : allMenu) {
                if (parentId.longValue() == source.getParentId().longValue()) {
                    MenuListVo menuVo = new MenuListVo();
                    BeanUtils.copyProperties(source, menuVo);
                    //递归查询子菜单，并封装信息
                    List<MenuListVo> childList = transferMenuVo(allMenu, source.getId());
                    if (!CollectionUtils.isEmpty(childList)) {
                        menuVo.setChildMenu(childList);
                    }
                    resultList.add(menuVo);
                }
            }
        }
        return resultList;
    }


    @Override
    public int addMenu(MenuDto menuDto) {
        TbMenu tbMenu = dealLevel(menuDto);
        //雪花算法生成ID
        tbMenu.setId(SnowIdUtil.nextId());
        return baseMapper.insert(tbMenu);
    }

    @Override
    @Transactional
    public int delMenu(Long id) {
        roleMenuRelMapper.delete(new LambdaQueryWrapper<TbRoleMenuRel>().eq(TbRoleMenuRel::getMenuId, id));
        return baseMapper.deleteById(id);
    }

    @Override
    @Transactional
    public int editMenu(MenuDto menuDto) {
        //判断一下状态是否被修改，如果修改为禁用状态,那么角色与菜单的关联关系也要删除
        StatusEnum nowStatus = menuDto.getStatus();
        StatusEnum statusBefore = baseMapper.selectById(menuDto.getId()).getStatus();
        if (!nowStatus.equals(statusBefore) && nowStatus==StatusEnum.DISABLE) {
            List<TbRoleMenuRel> tbRoleMenuRels = roleMenuRelMapper.selectList(new LambdaQueryWrapper<TbRoleMenuRel>()
                    .eq(TbRoleMenuRel::getMenuId, menuDto.getId()));
            for (TbRoleMenuRel tbRoleMenuRel : tbRoleMenuRels) {
                roleMenuRelMapper.deleteById(tbRoleMenuRel);
            }
        }
        //更新菜单信息
        TbMenu tbMenu = dealLevel(menuDto);
        return baseMapper.updateById(tbMenu);
    }

    private TbMenu dealLevel(MenuDto menuDto) {
        TbMenu menu = new TbMenu();
        BeanUtils.copyProperties(menuDto, menu);
        if (menuDto.getParentId() == null || menuDto.getParentId() == 0) {
            menu.setLevel(1);//根节点层级为1
            menu.setPath(null);//根节点路径为空
            menu.setParentId(0L);
        } else {
            TbMenu parentMenu = baseMapper.selectById(menuDto.getParentId());
            if (parentMenu == null) {
                throw CommonException.generate("未查询到对应父节点");
            }
            menu.setLevel(parentMenu.getLevel() + 1);
            if (StringUtils.isNotEmpty(parentMenu.getPath())) {
                menu.setPath(parentMenu.getPath() + "," + parentMenu.getId());
            } else {
                menu.setPath(parentMenu.getId().toString());
            }
            //如果上级节点原来是菜单类型、且当前节点也是菜单类型，那么上级节点改为目录类型
            // todo 这里也是要改成枚举的哦！
            if (parentMenu.getNodeType() == MenuTypeEnum.MENU && menu.getNodeType() == MenuTypeEnum.MENU) {
                parentMenu.setNodeType(MenuTypeEnum.CATALOG);
                baseMapper.updateById(parentMenu);
            }
        }
        return menu;
    }


    @Override
    public List<MenuListVo> getUserMenus(Long userId) {
        List<TbMenu> tbMenus = menuMapper.getUserMenus(userId);
        return transferMenuVo(tbMenus, 0L);
    }
}
